package org.bbb.library1.model;

import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Observable;
import java.util.Set;

/**
 * @author Rob Schellhorn
 */
public class Library extends Observable {

   private final Set<Book> books = new HashSet<Book>();

   /**
    * Adds the given book to this library. If the given book was part of the already already or if
    * the given book is a <code>null</code> reference nothing happens, otherwise this library is
    * marked as having changed.
    * 
    * @param book the book to add.
    */
   public void add(Book book) {
      assert invariant() : "PRE: The invariant holds";

      if (book != null && books.add(book)) {
         setChanged();
      }

      assert invariant() : "POST: The invariant holds";
   }

   /**
    * Retrieves a collection of all known books in this library. To change the collection use the
    * {@link #add(Book)} and {@link #remove(Book)} methods instead of changing the returned
    * collection directly.
    * 
    * @return a collection of all known books.
    * @see #add(Book)
    * @see #remove(Book)
    */
   public Collection<Book> getBooks() {
      assert invariant() : "PRE: The invariant holds";

      return Collections.unmodifiableCollection(books);
   }

   /**
    * Checks whether this instance satisfies the class invariant or not.
    * 
    * @return <code>true</code> if the class invariant is satisfied, <code>false</code>
    *         otherwise.
    */
   private boolean invariant() {
      return books != null;
   }

   /**
    * Removes the given book from this library. If the given book was not in the library or if the
    * given book is a <code>null</code> reference nothing happens, otherwise this library is
    * marked as having changed.
    * 
    * @param book the book to remove.
    */
   public void remove(Book book) {
      assert invariant() : "PRE: The invariant holds";

      if (book != null && books.remove(book)) {
         setChanged();
      }

      assert invariant() : "POST: The invariant holds";
   }
}
